import Excel from 'exceljs';
import { set, get } from 'lodash-es';

// 判断是否为 Object 对象
const isObject = obj => {
    return Object.prototype.toString.call(obj) === '[object Object]';
};

// 处理配置文件中定义的数据类型
const readTypeHandler = (type, value) => {
    if (!type) {
        return value;
    }
    if (value === null || value === undefined) {
        return value;
    }
    if (type === 'Number') {
        return Number(value);
    }
    if (type === 'Date') {
        return new Date(value);
    }
    if (type === 'Boolean') {
        const booleanMap = {
            是: true,
            否: false,
            yes: true,
            no: false,
            Yes: true,
            No: false,
            Y: true,
            N: false,
            y: true,
            n: false
        };
        if (booleanMap[value] !== undefined) {
            return booleanMap[value];
        } else {
            return !!value;
        }
    }
    return value;
};

const writeTypeHandler = (type, value) => {
    if (!type) {
        return value;
    }
    if (type === 'Number') {
        return Number(value);
    }
    if (type === 'Boolean') {
        const booleanMap = {
            true: '是',
            false: '否'
        };
        if (booleanMap[value] !== undefined) {
            return booleanMap[value];
        }
    }
    return value;
};

// 数字转换为26位英文字母
// number 从 1 开始
const number2ExcelAlphabet = (number = 1) => {
    let int;
    let remainder;
    let letter;
    if (number > 26) {
        int = parseInt(number / 26);
        remainder = number % 26;
        if (remainder > 0) {
            letter = `${String.fromCharCode(64 + int)}${String.fromCharCode(
                64 + remainder
            )}`;
        } else {
            letter = `${String.fromCharCode(64 + int - 1)}${String.fromCharCode(
                64 + 26
            )}`;
        }
    } else {
        int = number;
        letter = `${String.fromCharCode(64 + int)}`;
    }
    return letter;
};
/**
 * 将 ArrayBuffer 格式，创建文件并提示下载
 *
 * @param {*} data
 * @param {*} filename
 */
const downloadFile = (data, filename) => {
    if (!data) {
        return;
    }
    let url = window.URL.createObjectURL(new Blob([data]));
    let link = document.createElement('a');
    link.style.display = 'none';
    link.href = url;
    link.setAttribute('download', filename || `${new Date().getTime()}.xlsx`);
    document.body.appendChild(link);
    link.click();
};
/**
 * 读取文件并解析为 arrayBuffer 格式
 * @param {*} file
 *
 * @return {promise}
 */
export const readFile = file => {
    if (!file) {
        return;
    }
    return new Promise(resolve => {
        const reader = new FileReader();
        reader.onload = e => {
            const data = e.target.result;
            resolve(data);
        };
        reader.readAsArrayBuffer(file);
    });
};

/**
 * 根据 excel 配置文件解析为数据对象
 * @param {*} sheet
 * @param {*} config
 *
 * @return {Array} result
 */
export const parseDataByConfig = (sheet, config) => {
    const { rowCount, _rows } = sheet;
    const { startLine, columns } = config;
    const result = [];
    for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
        const line = rowIndex + 1;
        const rowItem = _rows[rowIndex];
        if (rowItem.values.length === 0) {
            break;
        }
        if (line >= startLine) {
            const rowData = {};
            columns.forEach((column, columnIndex) => {
                let scopeColumn = column;
                if (Array.isArray(column)) {
                    scopeColumn = column[column.length - 1];
                }
                const { key, type } = scopeColumn;
                const letter = number2ExcelAlphabet(columnIndex + 1);
                const cell = sheet.getCell(`${letter}${line}`);
                let { value } = cell;
                if (isObject(value)) {
                    value = value.text || '';
                }
                // 如果为时间格式字符串，则不去除空格
                if (value && value.toString().indexOf('时间') === -1) {
                    value = value
                        .toString()
                        .trim()
                        .replace(/\s/g, '');
                }
                value = readTypeHandler(type, value);
                set(rowData, key, value);
            });
            result.push(rowData);
        }
    }
    return result;
};

/**
 * 过滤数组中对象都是空置的对象返回新数组
 *
 * @param {*} data
 *
 * @return {Array}
 */
export const filterEmptyDataInArray = (data = []) => {
    return data.filter(item => {
        return Object.values(item).join('') !== '';
    });
};

const addBorderToCell = cell => {
    cell.border = {
        top: { style: 'thin' },
        left: { style: 'thin' },
        bottom: { style: 'thin' },
        right: { style: 'thin' }
    };
};

const addBgColorToCell = (cell, bgColor) => {
    cell.fill = {
        bgColor: { argb: `FF${bgColor.replace('#', '')}` },
        fgColor: { argb: `FF${bgColor.replace('#', '')}` },
        pattern: 'solid',
        type: 'pattern'
    };
};

const writeColumnsHeader = (sheet, config) => {
    const { columns = [], defaultWidth, defaultBorder } = config;
    let maxRowLength = 1;
    for (let maxRowIndex = 0; maxRowIndex < maxRowLength; maxRowIndex++) {
        columns.forEach((column, columnIndex) => {
            // 更新  maxRowLength 为 columns 中最大的数组长度
            if (column.length > maxRowLength) {
                maxRowLength = column.length;
            }
            let scopeColumn;
            if (Array.isArray(column)) {
                scopeColumn = column[maxRowIndex];
            } else {
                scopeColumn = column;
            }
            const { label, width, border, bgColor } = scopeColumn;
            const letter = number2ExcelAlphabet(columnIndex + 1);
            const cell = sheet.getCell(`${letter}${maxRowIndex + 1}`);
            cell.value = label;
            cell.alignment = { vertical: 'middle', horizontal: 'center' };
            // 设置 bgColor
            if (bgColor) {
                addBgColorToCell(cell, bgColor);
            }
            // 设置 border
            if (
                border === true ||
                (defaultBorder === true && border !== false)
            ) {
                addBorderToCell(cell);
            }
            // 设置 column width
            if (defaultWidth !== undefined || width !== undefined) {
                const sheetColumn = sheet.getColumn(`${letter}`);
                sheetColumn.width = width || defaultWidth;
            }
        });
    }
};

/**
 * 根据配置文件向sheet中写入数据
 *
 * @param {*} sheet
 * @param {*} config
 */
const writeColumnsBody = (sheet, config, data) => {
    const {
        columns = [],
        defaultData = [],
        startLine = 1,
        defaultBorder
    } = config;
    const scopeData = data || defaultData;
    scopeData.forEach((dataItem, dataIndex) => {
        columns.forEach((column, columnIndex) => {
            let scopeColumn = column;
            if (Array.isArray(column)) {
                scopeColumn = column[column.length - 1];
            }
            const { border, type, numFmt, key } = scopeColumn;
            const letter = number2ExcelAlphabet(columnIndex + 1);
            const cell = sheet.getCell(`${letter}${dataIndex + startLine}`);
            let value = get(dataItem, key);
            if (value !== undefined && value !== null && value !== '') {
                value = writeTypeHandler(type, value);
            }
            // 处理格式化
            if (value && numFmt) {
                cell.numFmt = numFmt;
            }
            // 处理对其方式
            cell.alignment = { vertical: 'middle', horizontal: 'center' };
            // 处理border
            if (
                border === true ||
                (defaultBorder === true && border !== false)
            ) {
                addBorderToCell(cell);
            }
            // 赋值
            cell.value = value;
        });
    });
};

const writeData = (sheet, config, data) => {
    // 写入 header
    writeColumnsHeader(sheet, config);
    writeColumnsBody(sheet, config, data);
};

/**
 * 根据配置解析文件
 *
 * @param {*} arrayBufferData
 * @param {*} config
 *
 * @return {promise} resultData
 */
export const parseFileByConfig = async (file, config) => {
    const arrayBufferData = await readFile(file);
    const workbook = new Excel.Workbook();
    await workbook.xlsx.load(arrayBufferData);
    const worksheet = workbook.worksheets[0];
    const data = parseDataByConfig(worksheet, config);
    const resultData = filterEmptyDataInArray(data);
    return resultData;
};

/**
 * 根据配置文件导出 excel 文件
 *
 * @param {*} file
 * @param {*} config
 */
export const exportFileByConfig = async (config, filename, data) => {
    // 创建 excel
    const workbook = new Excel.Workbook();

    // 添加文件信息
    workbook.creator = 'habby.fun.oa.system';
    workbook.created = new Date();
    workbook.modified = new Date();

    // 将工作簿日期设置为1904日期系统
    workbook.properties.date1904 = true;

    // 创建工作视图
    workbook.views = [
        {
            x: 0,
            y: 0,
            width: 10000,

            height: 20000,
            firstSheet: 0,
            activeTab: 1,

            visibility: 'visible'
        }
    ];

    // 添加 sheet
    const sheet = workbook.addWorksheet('Sheet1');

    // sheet 中添加数据和表头

    writeData(sheet, config, data);

    // 设置合并单元格
    const { merges = [] } = config;
    merges.forEach(merge => {
        sheet.mergeCells(merge);
    });

    const arrayBufferData = await workbook.xlsx.writeBuffer();

    downloadFile(arrayBufferData, filename);
};
